node.jsでYAMLに記述した式を評価して変換してみた
渡辺です。 テストデータのメンテは大変なんです。
お題
こんな定義があったとします。
const locations = { ENTRANCE: [100, 110], EXIT: [500, 510] };
これを踏まえて、YAMLでこんなデータを定義したいです。
- person_id: 101 x: 100 # ENTRANCE[0] y: 110 # ENTRANCE[1] - person_id: 102 x: 110 # ENTRANCE[0] + 10 y: 120 # ENTRANCE[1] + 10 - person_id: 103 x: 500 # EXIT[0] y: 510 # EXIT[1]
locations
は変わる可能性があるので、変わったときに再計算すると辛いんです。
YAMLに式が書きたいんです。
解決方法を考えてみましょう。 YAMLはフォーマットを少しいじっても構いませんが、YAMLとして読み込める(valid)であることは条件です。
.
.
.
.
.
解答例
こうやってみました。
- person_id: 101 x: <ENTRANCE[0]> y: <ENTRANCE[1]> - person_id: 102 x: <ENTRANCE[0] + 10> y: <ENTRANCE[1] + 10> - person_id: 103 x: <EXIT[0]> y: <EXIT[1]>
const fs = require('fs'); const YAML = require('yaml'); const locations = { ENTRANCE: [100, 110], EXIT: [500, 510] }; let data = YAML.parse(fs.readFileSync(`./data.yaml`, 'utf8')); const LOC = Object.keys(locations) .map(key => (`let ${key}=${JSON.stringify(locations[key])}`)) .join(';'); const conv = (data) => { const _conv = (obj) => { Object.keys(obj).forEach(key => { if (/^<.+>$/.test(obj[key])) { let value = obj[key].substring(1, obj[key].length - 1); obj[key] = eval(`${LOC};${value}`); } else if (typeof obj[key] === 'object') { _conv(obj[key]); } }); }; Object.keys(data).forEach(key => _conv(data[key])); return data; }; console.log(JSON.stringify(locations, null, 2)); console.log(JSON.stringify(data, null, 2)); console.log('----'); console.log(JSON.stringify(conv(data), null, 2));
実行結果
{ "ENTRANCE": [ 100, 110 ], "EXIT": [ 500, 510 ] } [ { "person_id": 101, "x": "<ENTRANCE[0]>", "y": "<ENTRANCE[1]>" }, { "person_id": 102, "x": "<ENTRANCE[0] + 10>", "y": "<ENTRANCE[1] + 10>" }, { "person_id": 103, "x": "<EXIT[0]>", "y": "<EXIT[1]>" } ] ---- [ { "person_id": 101, "x": 100, "y": 110 }, { "person_id": 102, "x": 110, "y": 120 }, { "person_id": 103, "x": 500, "y": 510 } ]
解説
式かどうか解るように <>
で囲みました。
式部分を評価する時に、 eval
を利用します。
この式の中で使う変数は、 locations
から作成します。
LOC
はゴニョゴニョ変換して、こんな感じ。
let ENTRANCE=[100,110];let EXIT=[500,510]
なので、
> eval('let ENTRANCE=[100,110];let EXIT=[500,510];ENTRANCE[0] + 10') 110
他になにか解決方法ないですかね?